#include <iostream>
#include <string>
using namespace std;

#include <tolua++.h>
#include <lua.hpp>
#include <lualib.h>
#include <lauxlib.h>

#include "Player.h"
#include "tolua_Player.h"
#include <assert.h>
void parameter_test(lua_State *L, Player *player) {
    if (luaL_dofile(L, "parameter_test.lua")) {
        lua_error(L);
        //std::cout << "parameter_test error" << std::endl;
    }
}
class CTest {
public:
    CTest(): mNum(0) { std::cout << "CTest created" << std::endl;}
    ~CTest(){std::cout << "CTest destroyed" << std::endl;};
    void setNum(lua_State *L, int num) {
        lua_getglobal(L, "add");
        tolua_pushnumber(L, mNum);
        tolua_pushnumber(L, num);
        if (lua_pcall(L, 2,1,0)) {
            lua_error(L);
        }   
        mNum = (int)lua_tointeger(L,-1);
        lua_pop(L, 1);
    } 
    int mNum;
};
void test_closure(lua_State *L) {
    if (luaL_dostring(L, "io.write(\"closure test(in function): player2 health = %d\"..player2:getHealth()..\"\\n\")")) {
        luaL_error(L, "closure player2 not found\n");
    }
}
int main()
{
    //
    // Perform initalization. TODO: Add error checking for tolua?
    //
    lua_State *L = lua_open();

    if (NULL == L) {
        cout << "Error Initializing lua\n";
        return -1;
    }

    luaL_openlibs(L);   // initalize all lua standard library functions
    tolua_open(L);          // initalize tolua
    tolua_Player_open(L);   // make Player class accessible from LUA

    //
    //  Run lua script to create player. This could also have been done using luaL_dostring().
    //
    
    luaL_dofile(L, "loadplayer.lua");
    //
    // Get the player object from lua
    //
    lua_getglobal(L, "player");
    Player* player = (Player*)tolua_tousertype(L, -1, 0);
    parameter_test(L, player);

    //------------------------------------------------------------------------------
    CTest test;
    if (luaL_dofile(L, "class_test.lua")) {
        lua_error(L);
    }
    test.setNum(L, 10);

    //------------------------------------------------------------------------------
    luaL_dofile(L, "assign.lua");
    //------------------------------------------------------------------------------
    //
    // Display health and change value
    //
    cout << "\nC++: Player's health is " << player->getHealth() << " - Now setting it to 6";
    player->setHealth(6);
    cout << "\nC++: Player's health is now " << player->getHealth() << "\n";

    //
    // The player object in LUA should now be updated. This code could also be put inside a lua script.
    //
    luaL_dostring(L, "io.write(\"LUA: Player's health is \"..player:getHealth()..\" - Now setting it to 11\")");
    luaL_dostring(L, "player:setHealth(11)");
    cout << endl;
    luaL_dostring(L, "io.write(\"LUA: Player's health is now \"..player:getHealth()..\"\\n\")");

    //==============================================================================
    // test closure
    Player *player2 = new Player();
    player2->setHealth(100);
    tolua_pushusertype(L, player2, "Player");
    lua_setglobal(L, "player2");
    if (luaL_dostring(L, "io.write(\"closure test: player2 health = \"..player2:getHealth()..\"\\n\")"))
        lua_error(L);
    test_closure(L);
    delete player2;
    if (luaL_dostring(L, "io.write(\"closure test: player2 health = \"..player2:getHealth()..\"\\n\")"))
        lua_error(L);
    //
    // Perform cleanup.
    //
    lua_close(L);
    return 0;
}

